home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / varie / uae-0_64.lha / uae-0.6.4 / src / disk.c < prev    next >
C/C++ Source or Header  |  1996-08-18  |  13KB  |  537 lines

  1.  /* 
  2.   * UAE - The Un*x Amiga Emulator
  3.   * 
  4.   * Floppy disk emulation
  5.   *
  6.   * (c) 1995 Bernd Schmidt, Hannu Rummukainen
  7.   */
  8.  
  9. #include "sysconfig.h"
  10. #include "sysdeps.h"
  11.  
  12. #include "config.h"
  13. #include "options.h"
  14. #include "memory.h"
  15. #include "events.h"
  16. #include "custom.h"
  17. #include "ersatz.h"
  18. #include "disk.h"
  19. #include "gui.h"
  20. #include "zfile.h"
  21.  
  22. #define FLOPPY_SPEED 5
  23.  
  24. UWORD* mfmwrite;
  25. static UWORD mfmwrbuffer[16384]; /* space for maximum disk DMA transfer */
  26.  
  27. static int side, direction, step;
  28. static UBYTE selected = 15;
  29. static int dskready;
  30. static int need_read = 0;
  31.  
  32. typedef struct {
  33.     UWORD sync;
  34.     UWORD len;
  35.     ULONG offs;
  36. } trackid;
  37.  
  38. typedef enum { ADF_NORMAL, ADF_EXT1 } drive_filetype;
  39. typedef struct {
  40.     FILE *diskfile;
  41.     drive_filetype filetype;
  42.     trackid trackdata[164];
  43.     unsigned int track;
  44.     int motoroff;
  45.     int wrprot;
  46.     UWORD bigmfmbuf[0x2000];
  47.     int tracklen;
  48.     unsigned long last_cycles;
  49.     int mfmpos;
  50. } drive;
  51.  
  52. drive floppy[4];
  53.  
  54. static void drive_fill_bigbuf(drive *drv);
  55.  
  56. static void drive_insert(drive *drv, int dnum, char *fname)
  57. {
  58.     unsigned char buffer[10];
  59.     
  60.     drv->diskfile = zfile_open(fname,"r+b");
  61.     if (drv->diskfile) {
  62.     drv->wrprot = 0;
  63.     } else {
  64.     drv->wrprot = 1;
  65.     drv->diskfile = zfile_open(fname, "rb");
  66.     if (!drv->diskfile) {
  67.         gui_filename(dnum, "");
  68.         return;
  69.     }
  70.     }
  71.     switch (dnum) {
  72.      case 0: strcpy((char *)df0, fname); break;
  73.      case 1: strcpy((char *)df1, fname); break;
  74.      case 2: strcpy((char *)df2, fname); break;
  75.      case 3: strcpy((char *)df3, fname); break;
  76.      case 4: break;
  77.     }
  78.     gui_filename(dnum, fname);
  79.     fread(buffer,sizeof(char),8,drv->diskfile);
  80.     if (strncmp((char *)buffer,"UAE--ADF",8) == 0) {    
  81.     int offs = 160*4+8;
  82.     int i;
  83.     
  84.         drv->filetype = ADF_EXT1;
  85.     drv->wrprot = 1; /* write to adf_ext1 not implemented */
  86.     for(i=0; i<160; i++) {
  87.         fread(buffer, 4, 1, drv->diskfile);
  88.         drv->trackdata[i].sync = buffer[0]*256 + buffer[1];
  89.         drv->trackdata[i].len = buffer[2]*256 + buffer[3];
  90.         drv->trackdata[i].offs = offs;
  91.         offs += drv->trackdata[i].len;
  92.     }
  93.     } else {
  94.     int i;
  95.         drv->filetype = ADF_NORMAL;
  96.     for(i=0; i<160; i++) {
  97.         drv->trackdata[i].len = 512 * 11;
  98.         drv->trackdata[i].sync = 0;
  99.         drv->trackdata[i].offs = i*512*11;
  100.     }
  101.     }
  102.     drive_fill_bigbuf(drv);
  103. }
  104.  
  105. static void drive_step(drive *drv)
  106. {
  107.     if (direction) {
  108.     if (drv->track) drv->track--;
  109.     } else {
  110.     if (drv->track < 85) drv->track++;
  111.     }
  112.     drive_fill_bigbuf(drv);
  113. }
  114.  
  115.  
  116. static int drive_track0(drive *drv) 
  117. {
  118.     return drv->track == 0; 
  119. }
  120.  
  121. static int drive_writeprotected(drive *drv) 
  122. {
  123.     return drv->wrprot || drv->diskfile == NULL; 
  124. }
  125.  
  126. static int drive_empty(drive *drv)
  127. {
  128.     return drv->diskfile == 0; 
  129. }
  130.  
  131. static int drive_running(drive *drv)
  132. {
  133.     return !drv->motoroff; 
  134. }
  135.  
  136. static void drive_motor(drive *drv, int off)
  137. {
  138.     if (drv->motoroff && !off) {
  139.     drv->last_cycles = cycles;
  140.     drv->mfmpos = 0;
  141.     eventtab[ev_diskindex].active = 1;
  142.     if (drv->tracklen)
  143.         eventtab[ev_diskindex].evtime = FLOPPY_SPEED * drv->tracklen + cycles;
  144.     else
  145.         eventtab[ev_diskindex].evtime = cycles + 1000;
  146.     eventtab[ev_diskindex].oldcycles = cycles;
  147.     } else if (off)
  148.     eventtab[ev_diskindex].active = 0;
  149.     drv->motoroff = off;
  150.     events_schedule();
  151.     
  152. }
  153.  
  154. static void drive_fill_bigbuf(drive *drv)
  155. {
  156.     int tr = drv->track*2 + side;
  157.     
  158.     if (!drv->diskfile) return;
  159.     
  160.     if (drv->trackdata[tr].sync == 0) {
  161.     /* Normal AmigaDOS format track */
  162.     int sec;
  163.     drv->tracklen = 11*544 + 300;
  164.     memset(drv->bigmfmbuf,0xaa,300*2);
  165.         
  166.     for (sec = 0; sec < 11; sec++) {
  167.         UBYTE secbuf[544];
  168.         int i;
  169.         UWORD *mfmbuf = drv->bigmfmbuf + 544*sec + 300;
  170.         ULONG deven,dodd;
  171.         ULONG hck=0,dck=0;
  172.         
  173.         secbuf[0] = secbuf[1] = 0x00;
  174.         secbuf[2] = secbuf[3] = 0xa1;
  175.         secbuf[4] = 0xff;
  176.         secbuf[5] = tr;
  177.         secbuf[6] = sec;
  178.         secbuf[7] = 11-sec;
  179.  
  180.         for(i = 8; i < 24; i++)
  181.         secbuf[i] = 0;
  182.     
  183.         fseek(drv->diskfile,
  184.           drv->trackdata[tr].offs + sec*512, 
  185.           SEEK_SET);
  186.         fread(&secbuf[32],1,512,drv->diskfile);
  187.     
  188.         mfmbuf[0] = mfmbuf[1] = 0xaaaa;
  189.         mfmbuf[2] = mfmbuf[3] = 0x4489;
  190.     
  191.         deven = ((secbuf[4] << 24) | (secbuf[5] << 16) 
  192.              | (secbuf[6] << 8) | (secbuf[7]));
  193.         dodd = deven >> 1;
  194.         deven &= 0x55555555; dodd &= 0x55555555;
  195.     
  196.         mfmbuf[4] = dodd >> 16;
  197.         mfmbuf[5] = dodd;
  198.         mfmbuf[6] = deven>> 16; 
  199.         mfmbuf[7] = deven;
  200.     
  201.         for (i = 8; i < 48; i++)
  202.         mfmbuf[i] = 0;
  203.         for (i = 0; i < 512; i += 4){
  204.         deven = ((secbuf[i+32] << 24) | (secbuf[i+33] << 16)
  205.              | (secbuf[i+34] << 8) | (secbuf[i+35]));
  206.         dodd = deven >> 1;
  207.         deven &= 0x55555555; dodd &= 0x55555555;
  208.         mfmbuf[(i>>1)+32] = dodd >> 16;
  209.         mfmbuf[(i>>1)+33] = dodd;
  210.         mfmbuf[(i>>1)+256+32] = deven >> 16;
  211.         mfmbuf[(i>>1)+256+33] = deven;
  212.         }
  213.     
  214.         for(i = 4; i < 24; i += 2)
  215.         hck ^= (mfmbuf[i] << 16) | mfmbuf[i+1];
  216.     
  217.         deven = dodd = hck; dodd >>= 1;
  218.         mfmbuf[24] = dodd >> 16; mfmbuf[25] = dodd;
  219.         mfmbuf[26] = deven>> 16; mfmbuf[27] = deven;
  220.     
  221.         for(i = 32; i < 544; i += 2)
  222.         dck ^= (mfmbuf[i] << 16) | mfmbuf[i+1];
  223.     
  224.         deven = dodd = dck; dodd >>= 1;
  225.         mfmbuf[28] = dodd >> 16; mfmbuf[29] = dodd;
  226.         mfmbuf[30] = deven>> 16; mfmbuf[31] = deven;
  227.     }
  228.     } else {
  229.     int i;
  230.     drv->tracklen = drv->trackdata[tr].len/2 + 1;
  231.     drv->bigmfmbuf[0] = drv->trackdata[tr].sync;
  232.     fseek(drv->diskfile, drv->trackdata[tr].offs, SEEK_SET);
  233.     fread(drv->bigmfmbuf+1, 1, drv->trackdata[tr].len, drv->diskfile);
  234.     for (i = 0; i < drv->trackdata[tr].len/2; i++) {
  235.         UWORD *mfm = drv->bigmfmbuf + i + 1;
  236.         UBYTE *data = (UBYTE *)mfm;
  237.         
  238.         *mfm = 256 * *data + *(data+1);
  239.     }
  240.     }
  241.     need_read = 0;
  242.     drv->last_cycles = cycles;
  243.     drv->mfmpos = 0;
  244. }
  245.  
  246. static int drive_get_data(drive *drv, UWORD *mfm, UWORD *byt)
  247. {
  248.     int offset,mfmpos;
  249.     if (need_read) {
  250.     drive_fill_bigbuf(drv);
  251.     }
  252.     offset = (cycles - drv->last_cycles) / FLOPPY_SPEED;
  253.     mfmpos = (drv->mfmpos + offset) % drv->tracklen;
  254.     drv->last_cycles += offset*FLOPPY_SPEED;
  255.     drv->mfmpos = mfmpos;
  256.     *mfm = drv->bigmfmbuf[mfmpos];
  257.     return offset > 0;
  258. }
  259.  
  260. #define MFMMASK 0x55555555
  261. static __inline__ ULONG getmfmlong(UWORD* mbuf) 
  262. {
  263.     return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK;
  264. }
  265.  
  266. static void drive_write_data(drive *drv, UWORD *mbuf, int length)
  267. {
  268.     int i, secwritten = 0;
  269.     ULONG odd, even, chksum, id, dlong;
  270.     UBYTE* secdata;
  271.     UBYTE secbuf[544];
  272.     UWORD *mend = mbuf + length;
  273.     
  274.     if (drive_writeprotected(drv)) return;
  275.     mend -= (4 + 16 + 8 + 512);
  276.     while (length > 0) {
  277.     int trackoffs;
  278.     
  279.     do {
  280.         while (*mbuf++ != 0x4489) {
  281.         if (mbuf >= mend) return;
  282.         }
  283.     } while (*mbuf++ != 0x4489);
  284.     
  285.     odd = getmfmlong(mbuf);
  286.     even = getmfmlong(mbuf+2);
  287.     mbuf += 4;    
  288.     id = (odd << 1) | even;
  289.     
  290.     trackoffs = (id & 0xff00) >> 8;
  291.     if (trackoffs > 10) {
  292.         printf("Disk write: weird sector number %d\n", trackoffs);
  293.         continue;
  294.     }
  295.     chksum = odd ^ even;
  296.     for (i=0; i<4; i++) {
  297.         odd = getmfmlong(mbuf);
  298.         even = getmfmlong(mbuf+8);
  299.         mbuf += 2;
  300.         
  301.         dlong = (odd << 1) | even;
  302.         if (dlong)  secwritten = -200;
  303.         chksum ^= odd ^ even;
  304.     }  /* could check here if the label is nonstandard */
  305.     mbuf += 8;
  306.     odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4;
  307.     if ((((odd << 1) | even) != chksum) || 
  308.         (((id & 0x00ff0000) >> 16) != drv->track*2 + side)) {
  309.         printf("Disk write: checksum error on sector header\n");
  310.         continue;
  311.     }
  312.     odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4;
  313.     chksum = (odd << 1) | even;
  314.     secdata = secbuf + 32;
  315.     for (i=0; i<128; i++) {
  316.         odd = getmfmlong(mbuf); even = getmfmlong(mbuf+256); mbuf += 2;
  317.         dlong = (odd << 1) | even;
  318.         *secdata++ = dlong >> 24; *secdata++ = (dlong >> 16) & 0xff;
  319.         *secdata++ = dlong >> 8; *secdata++ = dlong;
  320.         chksum ^= odd ^ even;
  321.     }
  322.     mbuf += 256;
  323.     if (chksum) {
  324.         printf("Disk write: data checksum error\n");
  325.         continue;
  326.     }
  327.     secwritten++;
  328.     fseek(drv->diskfile, 
  329.           drv->trackdata[drv->track*2 + side].offs + trackoffs*512,
  330.           SEEK_SET);
  331.     fwrite(secbuf+32, sizeof(UBYTE), 512, drv->diskfile);
  332.     }
  333.     need_read = 1;
  334.     
  335.     if (secwritten == 0) 
  336.     printf("Disk write in unsupported format\n");
  337.     if (secwritten < 0)
  338.     printf("Disk write: sector labels ignored\n");
  339. }
  340.  
  341.  
  342. static void drive_eject(drive *drv)
  343. {
  344.     if (!drive_empty(drv)) zfile_close(drv->diskfile);
  345.     drv->diskfile = 0;
  346. }
  347.  
  348. /* We use this function if we have no Kickstart ROM. 
  349.  * No error checking - we trust our luck. */
  350. void DISK_ersatz_read (int tr, int sec, CPTR dest)
  351. {
  352.     int i;
  353.     UBYTE *dptr = get_real_address(dest);
  354.     fseek(floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec*512, SEEK_SET);
  355.     fread(dptr,1,512,floppy[0].diskfile);
  356. }
  357.  
  358. void disk_eject(int num)
  359. {
  360.     gui_filename(num, "");
  361.     drive_eject(floppy + num);
  362. }
  363.  
  364. void disk_insert(int num, char *name)
  365. {
  366.     /* just to be sure */
  367.     drive_eject(floppy + num);
  368.     drive_insert(floppy + num, num, name);
  369. }
  370.  
  371. int disk_empty(int num)
  372. {
  373.     return drive_empty(floppy + num);
  374. }
  375.  
  376. void DISK_init()
  377. {
  378.     drive_insert(floppy, 0, df0);
  379.     if (disk_empty(0))
  380.     fprintf(stderr, "No floppy in drive 0.\n");
  381.     drive_insert(floppy + 1, 1, df1);
  382.     drive_insert(floppy + 2, 2, df2);
  383.     drive_insert(floppy + 3, 3, df3);
  384. }
  385.  
  386. static int ledstate[] = { 0,0,0,0 };
  387.  
  388. void DISK_select(UBYTE data)
  389. {
  390.     int step_pulse;
  391.     int dr;
  392.     
  393.     if (selected != ((data >> 3) & 15)) 
  394.     dskready = 0;
  395.     selected = (data >> 3) & 15;
  396.     if (side != 1 - ((data >> 2) & 1)) {
  397.     side = 1 - ((data >> 2) & 1);
  398.     need_read = 1;
  399.     }
  400.     direction = (data >> 1) & 1;
  401.     step_pulse = data & 1;
  402.     if (step != step_pulse) {
  403.     step = step_pulse;
  404.     if (step == 0){
  405.         for (dr = 0; dr < 4; dr++){
  406.         if (!(selected & (1 << dr))) {
  407.             drive_step(floppy + dr);
  408.         }
  409.         }
  410.     }
  411.     }
  412.     for (dr = 0; dr < 4; dr++){
  413.     if (!(selected & (1<<dr))) {
  414.         drive_motor(floppy + dr, data >> 7);
  415.     }
  416.     }
  417.     for (dr = 0; dr < 4; dr++) {
  418.     int state = (!(selected & (1<<dr))) | !floppy[dr].motoroff;
  419.     if (state != ledstate[dr])
  420.         gui_led (dr+1, state);
  421.     ledstate[dr] = state;
  422.     }
  423. }
  424.  
  425. UBYTE DISK_status()
  426. {
  427.     UBYTE st = 0x3c;
  428.     int dr;
  429.     
  430.     for (dr = 0; dr < 4; dr++){
  431.     if (!(selected & (1 << dr))) {
  432.         if (drive_running(floppy + dr)){
  433.         if (dskready) st &= ~0x20;
  434.         dskready = 1;
  435.         } else {
  436.         st &= ~0x20; /* report drive ID */
  437.         }
  438.         
  439.         if (drive_track0(floppy + dr)) { st &= ~0x10; }
  440.         if (drive_writeprotected(floppy + dr)) { st &= ~8; }
  441.         if (drive_empty(floppy + dr)) { st &= ~0x4; }
  442.     }
  443.     }
  444.     return st;
  445. }
  446.  
  447. int DISK_GetData(UWORD *mfm,UWORD *byt)
  448. {
  449.     int dr;
  450.     for (dr = 0; dr < 4; dr++){
  451.     if (!(selected & (1<<dr))) {
  452.         return drive_get_data (floppy + dr, mfm, byt);
  453.     }
  454.     }
  455.     return 0;
  456. }
  457.  
  458. static UWORD mfm_read_buffer[0x4000];
  459. static int mfm_read_length;
  460.  
  461. int DISK_PrepareReadMFM(int length, UWORD sync, int use_sync)
  462. {
  463.     int dr;
  464.     
  465.     mfm_read_length = 0;
  466.     
  467.     for (dr = 0; dr < 4; dr++) {
  468.     if (!(selected & (1<<dr))) {
  469.         int time = 0;
  470.         UWORD *mfmp = mfm_read_buffer;
  471.         drive *drv = floppy + dr;
  472.         int offset,mfmpos;
  473.  
  474.         if (need_read) {
  475.         drive_fill_bigbuf(drv);
  476.         }
  477.         
  478.         offset = (cycles - drv->last_cycles) / FLOPPY_SPEED;
  479.         mfmpos = (drv->mfmpos + offset) % drv->tracklen;
  480.         drv->last_cycles += offset*FLOPPY_SPEED;
  481.         drv->mfmpos = mfmpos;
  482.         mfmpos++; mfmpos %= drv->tracklen;
  483.         while (drv->bigmfmbuf[mfmpos] != sync && mfmpos != drv->mfmpos && use_sync)
  484.         mfmpos = (mfmpos + 1) % drv->tracklen, time++;
  485.         
  486.         if (drv->bigmfmbuf[mfmpos] != sync && use_sync) {
  487.         fprintf(stderr, "warning: sync not found on disk read\n");
  488.         return 0;
  489.         } else
  490.         mfmpos++;
  491.         
  492.         mfm_read_length = length;
  493.  
  494.         while (length--) {
  495.         *mfmp++ = drv->bigmfmbuf[mfmpos];
  496.         mfmpos = (mfmpos + 1) % drv->tracklen;
  497.         time++;
  498.         }
  499.  
  500.         return time*FLOPPY_SPEED;
  501.     }
  502.     }
  503.     return 0;    
  504. }
  505.  
  506. int DISK_ReadMFM(CPTR target)
  507. {
  508.     int i;
  509.     UBYTE *mfmp = get_real_address(target);
  510.     
  511.     if (!chipmem_bank.check(target, mfm_read_length * 2)) {
  512.     fprintf(stderr, "warning: Bad disk DMA read pointer\n");
  513.     return 0;
  514.     }
  515.  
  516.     for (i = 0; i < mfm_read_length; i++) {
  517.     *mfmp++ = mfm_read_buffer[i] >> 8;
  518.     *mfmp++ = mfm_read_buffer[i];
  519.     }
  520.     return 1;
  521. }
  522.  
  523. void DISK_InitWrite()
  524. {
  525.     mfmwrite = mfmwrbuffer;
  526. }
  527.  
  528. void DISK_WriteData(int length)
  529. {
  530.     int dr;
  531.     for (dr=0;dr<4;dr++){
  532.     if (!(selected & (1<<dr))) {
  533.         drive_write_data(floppy + dr, mfmwrbuffer, length);
  534.     }
  535.     }
  536. }
  537.